package com.gitee.wsl.ext.array

import kotlin.random.Random

/**
 * Creates [IntArray] with random indices
 * @param count number of indices
 */
fun IntRange.indicesByRandom(count: Int, random: Random): IntArray {
    if (count > last - first) throw IllegalStateException("Count cannot be more than size")
    val randomIndices = IntArray(count)
    repeat(count) { counter ->
        var index = random.nextInt(first, last)
        while (randomIndices.inUntil(index, counter)) {
            index = ++index % last
        }
        randomIndices[counter] = index
    }
    return randomIndices
}

/**
 * Creates [IntArray] with random indices
 * @param count number of indices, `count < size`
 * @param size maximum indices count (exclusive)
 */
fun indicesByRandom(count: Int, size: Int, random: Random): IntArray {
    if (count > size) throw IllegalStateException("Count cannot be more than size")

    return if (size > 5000 && count > size / 4) {
        val newAr = IntArray(size) { it }
        newAr.shuffle(random)
        newAr.copyOf(count)
    } else {
        val randomIndices = IntArray(count)
        repeat(count) { counter ->
            var index = random.nextInt(0, size)
            while (randomIndices.inUntil(index, counter)) {
                index = ++index % size
            }
            randomIndices[counter] = index
        }
        randomIndices
    }
}

/**
 * Creates [Array] with random elements from source array
 * @param count number of random elements
 */
inline fun <reified T> Array<out T>.random(count: Int, random: Random): Array<T> {
    val indices = indicesByRandom(count, size, random)
    return Array(count) { get(indices[it]) }
}

fun <T> Array<T>.getRandom(generator: Random = Random): T = get(generator.nextInt(size))
